package Database;

import com.mysql.jdbc.ExceptionInterceptor;
import com.mysql.jdbc.Extension;
import com.mysql.jdbc.MySQLConnection;
import com.mysql.jdbc.log.Log;
import java.security.MessageDigest;
import java.sql.*;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Formatter;
import java.util.Map;
import java.util.Properties;
import java.util.TimeZone;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class SQLInterface {

    static public int userType = -1;
    static public String userName = null;
    static public int userNameInt = -1;
    static public boolean connected = false;
    final private static String url = "jdbc:mysql://192.168.56.101:3306";
    //final private static String url = "jdbc:microsoft:sqlserver://192.168.56.101:3306";
    private static Connection conn = null;

    public static class Wiadomosci {

        public static class Wiadomosc {

            public int id;
            public int idNadawcy;
            public String nadawca;
            public String temat;
            public String tresc;
            public boolean przeczytane;
            public Time czas;

            public Wiadomosc(int id, int idNadawcy, String nadawca, String temat, String tresc, boolean przeczytane, Time czas, Date data) {
                this.id = id;
                this.idNadawcy = idNadawcy;
                this.nadawca = nadawca;
                this.temat = temat;
                this.tresc = tresc;
                this.przeczytane = przeczytane;
                this.czas = new Time(czas.getTime()+data.getTime());
                
            }
        }

        public static void Wyslij(String temat, String tresc, int adresat) throws SQLException {
            PreparedStatement st = conn.prepareCall("call dziennik.WyslijWiadomosc(?,?,?)");
            st.setInt(1, adresat);
            st.setString(2, temat);
            st.setString(3, tresc);
            st.executeUpdate();
            st.close();
        }

        public static ArrayList<Wiadomosc> PobierzWiadomosci() throws Exception {
            ArrayList<Wiadomosc> listaWiadomosci = new ArrayList<>();
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.uczen_wiadomosci");
            while (rs.next()) {
                //id idnadawcy przeczytana tytul imie nazwisko temat tresc
                String nadawca = rs.getString(4) + " " + rs.getString(5) + " " + rs.getString(6);
                Wiadomosc temp = new Wiadomosc(rs.getInt(1), rs.getInt(2), nadawca, rs.getString(7), rs.getString(8), rs.getBoolean(3), rs.getTime(9), rs.getDate(9));
                listaWiadomosci.add(temp);
            }
            rs.close();
            st.close();
            return listaWiadomosci;
        }

        public static void OznaczJakoPrzeczytane(ArrayList<Integer> listaId) throws Exception {
            PreparedStatement st = conn.prepareStatement("update dziennik.uczen_wiadomosci set przeczytana = true where id = ?");
            for (Integer i : listaId) {
                st.setInt(1, i);
                st.executeUpdate();
            }
            st.close();
        }

        public static void OznaczJakoPrzeczytane(int id) throws Exception {
            PreparedStatement st = conn.prepareStatement("update dziennik.uczen_wiadomosci set przeczytana = true where id = ?");
            st.setInt(1, id);
            st.executeUpdate();
            st.close();
        }

        public static void Usun(int id) throws Exception {
            //pamietaj o triggerze w tabeli wiadomosci
            PreparedStatement st = conn.prepareStatement("delete from dziennik.wiadomosci where id = ?");
            st.setInt(1, id);
            st.executeUpdate();
            st.close();
        }

        public static void Usun(ArrayList<Integer> listaId) throws Exception {
            PreparedStatement st = conn.prepareStatement("delete from dziennik.wiadomosci where id = ?");
            for (Integer i : listaId) {
                st.setInt(1, i);
                st.executeUpdate();
            }
            st.close();
        }
    }

    public static class Oceny {

        public static class Ocena_DlaUcznia {

            public Date data;
            public float ocena;
            public int waga;
            public String zaCo;
            public String nazwaPrzedmiotu;
        }

        public static ArrayList<Ocena_DlaUcznia> PobierzOcenyUcznia() throws Exception {
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.uczen_oceny");
            ArrayList<Ocena_DlaUcznia> listaOcen;
            listaOcen = new ArrayList<>();

            while (rs.next()) {
                Ocena_DlaUcznia temp = new Ocena_DlaUcznia();
                temp = new Ocena_DlaUcznia();
                temp.ocena = rs.getFloat(1);
                temp.waga = rs.getInt(2);
                temp.zaCo = rs.getString(3);
                temp.data = rs.getDate(4);
                temp.nazwaPrzedmiotu = rs.getString(5);
                listaOcen.add(temp);
            }
            return listaOcen;
        }
    }

    public static class Przedmioty {

        public static class Przedmiot_DlaUcznia {

            public String tytulNaukowy;
            public String imie;
            public String nazwisko;
            public String nazwa;
        }

        public static ArrayList<Przedmiot_DlaUcznia> PobierzPrzedmiotyUcznia() throws Exception {
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.uczen_przedmioty");
            ArrayList<Przedmiot_DlaUcznia> listaPrzedmiotow;
            listaPrzedmiotow = new ArrayList<>();
            while (rs.next()) {
                Przedmiot_DlaUcznia temp = new Przedmiot_DlaUcznia();
                temp.nazwa = rs.getString(1);
                temp.tytulNaukowy = rs.getString(2);
                temp.imie = rs.getString(3);
                temp.nazwisko = rs.getString(4);
                listaPrzedmiotow.add(temp);
            }
            return listaPrzedmiotow;
        }
    }

    public static class Nauczyciele {

        public static class Nauczyciel_DlaUcznia {

            public int userId;
            public String imie;
            public String nazwisko;
            public String tytulNaukowy;
            public boolean twojNauczyciel;
        }

        public static ArrayList<Nauczyciel_DlaUcznia> PobierzListeNauczycieli() throws Exception {
            ArrayList<Nauczyciel_DlaUcznia> listaNauczycieli = new ArrayList<>();
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.uczen_listanauczycieli");
            while (rs.next()) {
                //id imie nazwisko tytul pracuje userid
                Nauczyciel_DlaUcznia n = new Nauczyciel_DlaUcznia();
                n.userId = rs.getInt(1);
                n.imie = rs.getString(2);
                n.nazwisko = rs.getString(3);
                n.tytulNaukowy = rs.getString(4);
                n.twojNauczyciel = rs.getBoolean(5);
                listaNauczycieli.add(n);
            }
            return listaNauczycieli;
        }
    }

    public static class Uwagi {

        public static class Uwaga {

            public Date data;
            public String wystawiajacy;
            public String tresc;
        }

        public static ArrayList<Uwaga> PobierzUwagiUcznia() throws Exception {
            ArrayList<Uwaga> listaUwag;
            listaUwag = new ArrayList<>();
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.uczen_uwagi");

            while (rs.next()) {
                Uwaga temp = new Uwaga();
                temp.data = rs.getDate(1);
                temp.wystawiajacy = rs.getString(2)
                        + " "
                        + rs.getString(3)
                        + " "
                        + rs.getString(4);
                temp.tresc = rs.getString(5);
                listaUwag.add(temp);
            }
            return listaUwag;
        }
    }

    public static class Planlekcji {

        public static class RekordPlanuLekcji {

            public int jednostka;
            public String przedmiot;
            public int dzienTygodnia;
        }

        public static ArrayList<RekordPlanuLekcji> PobierzPlanLekcjiUcznia() throws Exception {
            ArrayList<RekordPlanuLekcji> plan = new ArrayList<>();
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.uczen_planlekcji");
            while (rs.next()) {
                RekordPlanuLekcji temp = new RekordPlanuLekcji();
                temp.jednostka = rs.getInt(2);
                temp.przedmiot = rs.getString(3);
                temp.dzienTygodnia = rs.getInt(1);
                plan.add(temp);
            }
            return plan;
        }

        public static ArrayList<String> PobierzJednostki() throws Exception {
            ArrayList<String> jednostki = new ArrayList<>();
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.jednostki");
            Format format = new SimpleDateFormat("H:mm");
            while (rs.next()) {
                java.util.Date czas1 = rs.getTime(2);
                java.util.Date czas2 = rs.getTime(3);
                String jednostka = format.format(czas1) + " - " + format.format(czas2);
                jednostki.add(jednostka);
            }
            return jednostki;
        }
    }

    public static class OcenyKoncowe {
        private static String OcenaZZachowaniaString(int ocena){
            switch(ocena){
                case 1: return "naganne";
                case 2: return "nieodpowiednie";
                case 3: return "poprawne";
                case 4: return "dobre";
                case 5: return "bardzo dobre";
                case 6: return "wzorowe";
            }
            return "blad!";
        }
        public static ArrayList<RekordOcenKoncowych> PobierzOcenyKoncowe() throws Exception {
            ArrayList<RekordOcenKoncowych> ret = new ArrayList<RekordOcenKoncowych>();
            Statement st_przedmioty = conn.createStatement();
            Statement st_zachowanie = conn.createStatement();
            Statement st_zachowanieKoncowe = conn.createStatement();
            Statement st_ocenyKoncowe = conn.createStatement();
            ResultSet rs_przedmioty = st_przedmioty.executeQuery("select * from dziennik.uczen_przedmioty");
            ResultSet rs_zachowanie = st_zachowanie.executeQuery("select * from dziennik.uczen_zachowanie");
            ResultSet rs_zachowanieKoncowe = st_zachowanieKoncowe.executeQuery("select * from dziennik.uczen_zachowaniekoncowe");
            ResultSet rs_ocenyKoncowe = st_ocenyKoncowe.executeQuery("select * from dziennik.uczen_ocenykoncowe");


            while (rs_przedmioty.next()) {
                String nauczyciel = rs_przedmioty.getString(2) + " " + rs_przedmioty.getString(3) + " " + rs_przedmioty.getString(4);
                String przedmiot = rs_przedmioty.getString(1);
                RekordOcenKoncowych temp = new RekordOcenKoncowych(przedmiot, nauczyciel);
                int ocenaKoncowa;
                int zachowanieKoncowe;
                rs_zachowanie.beforeFirst();
                boolean wpisaneKoncoweZachowanie = false;
                while (rs_zachowanie.next()) {
                    if (rs_zachowanie.getString(4).equals(temp.przedmiot)){
                        if(rs_zachowanie.getBoolean(2)){//jesli to jest proponowana
                            temp.zachowanie = OcenaZZachowaniaString(rs_zachowanie.getInt(1));
                            temp.zachowanie_proponowane = true;
                        }
                        else{
                            temp.zachowanie = OcenaZZachowaniaString(rs_zachowanie.getInt(1));
                            temp.zachowanie_proponowane = false;
                            break;
                        }
                    }
                }
                rs_ocenyKoncowe.beforeFirst();
                while(rs_ocenyKoncowe.next()){
                    if(rs_ocenyKoncowe.getString(4).equals(temp.przedmiot)){
                        if(rs_ocenyKoncowe.getBoolean(3)){
                            temp.ocena = Integer.toString(rs_ocenyKoncowe.getInt(1));
                            temp.ocena_proponowana = true;
                        }
                        else{
                            temp.ocena = Integer.toString(rs_ocenyKoncowe.getInt(1));
                            temp.ocena_proponowana = false;
                            break;
                        }
                    }
                }
                ret.add(temp);
            }


            rs_zachowanie.close();
            rs_ocenyKoncowe.close();
            rs_przedmioty.close();
            rs_zachowanieKoncowe.close();
            st_zachowanie.close();
            st_ocenyKoncowe.close();
            st_przedmioty.close();
            st_zachowanieKoncowe.close();
            return ret;
        }
        public static String PobierzZachowanieKoncowe() throws Exception{
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.uczen_zachowaniekoncowe");
            String ret = "";
            while(rs.next()){                
                if(!rs.getBoolean(2)){
                    ret = OcenaZZachowaniaString(rs.getInt(1));
                    break;
                }
                else {
                    ret = OcenaZZachowaniaString(rs.getInt(1)) + "*";
                }
            }
            return ret;
        }
        public static class RekordOcenKoncowych {

            public String ocena;
            public String zachowanie;//
            public String przedmiot;//
            public String nauczyciel;//
            public Boolean zachowanie_proponowane;//
            public Boolean ocena_proponowana;

            RekordOcenKoncowych(String przedmiot, String nauczyciel) {
                this.przedmiot = przedmiot;
                this.nauczyciel = nauczyciel;
                zachowanie_proponowane = false;
                ocena_proponowana = false;
                zachowanie = "";
                ocena = "";
            }
        }
    }

    public static class DaneOsobowe {

        public static String[] Uczen_PobierzDaneOsobowe() throws Exception {
            String[] dane = new String[3];
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.uczen_daneosobowe");
            rs.next();
            dane[0] = rs.getString(1);
            dane[1] = rs.getString(2);
            dane[2] = rs.getString(3);
            rs.close();
            st.close();
            return dane;
        }

        public static String[] Uczen_PobierzDaneWychowawcy() throws Exception {
            String[] dane = new String[4];
            Statement st = conn.createStatement();
            ResultSet rs = st.executeQuery("select * from dziennik.uczen_danewychowawcy");
            rs.next();
            dane[0] = rs.getString(3);
            dane[1] = rs.getString(1);
            dane[2] = rs.getString(2);
            dane[3] = rs.getString(5);
            while (rs.next()) {
                dane[3] += ", " + rs.getString(5);
            }
            rs.close();
            st.close();
            return dane;
        }
    }

    public static String Hash(String haslo) {
        MessageDigest md = null;
        byte[] bytes = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
            bytes = haslo.getBytes("UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        bytes = md.digest(md.digest(bytes));
        Formatter formatter = new Formatter();
        for (int i = 0; i != bytes.length; i++) {
            formatter.format("%02x", bytes[i]);
        }
        String result = "*" + formatter.toString().toUpperCase();
        formatter.close();
        return result;
    }

    public static boolean ZmienHaslo(String stareHaslo, String noweHaslo) throws Exception {

        CallableStatement st = conn.prepareCall("{call dziennik.zmienHaslo(?,?,?)}");
        st.setString(1, Hash(stareHaslo));
        st.setString(2, Hash(noweHaslo));
        st.registerOutParameter(3, java.sql.Types.BOOLEAN);
        st.executeUpdate();
        return st.getBoolean(3);
    }

    public static boolean Login(String login, String password) throws SQLException{
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }


        if (login == null || password == null) {
            return false;
        } 
        else {
            DriverManager.setLoginTimeout(3);
            //conn.setNetworkTimeout(Executors.newSingleThreadExecutor(), 3);
            
            
            conn = DriverManager.getConnection(url + "?user=" + login + "&password=" + password + "&noAccessToProcedureBodies=true&useInformationSchema=true");
            conn.setAutoCommit(true);
            connected = true;

            Statement st = conn.createStatement();

            try {
                ResultSet rs;
                rs = st.executeQuery("select dziennik.GetUserType();");
                rs.next();
                userType = rs.getInt(1);

                rs = st.executeQuery("select dziennik.GetUserName();");
                rs.next();
                userName = rs.getString(1);

                rs = st.executeQuery("select dziennik.GetUserNameInt();");
                rs.next();
                userNameInt = rs.getInt(1);

                return true;
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
                return false;
            }
        }
    }

    public static void Logout() {
        try {
            conn.close();
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }

        userType = -1;
        userName = null;
        userNameInt = -1;
        connected = false;
    }
}